Strategy Pattern

假设我们要实现鸭子对象及其行为,假设鸭子行为有鸣叫,颜色,飞行等。

Several method

With Extending

很自然的做法是定义一个鸭子父类,然后定义特定鸭子的子类。

由于不同的鸭子有不同的鸣叫,颜色,飞行等行为,如果把这些行为都放在鸭子父类中,则会导致部分不具有这些行为的鸭子也变得具有这些行为,一种弥补方法是对于这些行为什么都不做,但是会导致代码僵化,如果需要改动则需要修改所有鸭子的代码。

With Interface

  • 另一种实现方法是使用接口,把会飞,会叫这些行为各自独立抽象出接口,对于需要具有这些行为的鸭子,使这些鸭子实现相应的接口即可。看起来很不错,但是一个问题是,接口不具有实现代码,也就是无法达到代码的复用,如果某种功能需要更改,比如飞行行为。在这个问题下,如果许多鸭子其实是具有相同的飞行行为的,如果需要进行调整,则同样需要修改所有这些鸭子的飞行行为。

Strategy mode

这里问题的关键是:没有分离出变化部分和稳定部分。一个设计原则是:

找出应用中可能需要变化之处,把它们独立出来,不要和哪些不需要变化的代码混在一起。

  • 根据上面的分析,我们应该把变化的部分和不变的不变的部分区分开来。

假设在这个问题下fly()和quack()行为是会随着鸭子的不同而改变的,但并不是每种鸭子的行为都是不同功能的,部分鸭子会共享某种飞行行为或quack行为。这里我们不使用接口来抽象这些行为,因为前面提到,部分鸭子会共享某种飞行行为或quack行为,使用抽象则会导致无法复用这些代码。这里我们分别建立一组抽象来代表每个行为(可以为接口)。

然后对于几种不同的行为,分别实现具体类继承定义的抽象behavior。然后在鸭子类引用这些类的实例,通过调用这些实例的实现方法来实现鸭子的相应行为。也就是具体行为的实现是在这些具体行为类中实现的,鸭子只是调用这些实现方法来实现相应行为。

上面解释的过于抽象,简单说来关键在于:
鸭子现在将飞行和鸣叫的动作『委托』别人处理(独立的behavior接口),而不是定义在鸭子类内部的飞行方法或鸣叫方法(仍然会有相关方法,但是其内容就是简单的引用behavior类的具体实现)。

1
2
3
4
5
6
7
public class Duck {
FlyBehaviour flyb;

public void performFly() {
flyb.fly(); // 委托给行为类
}
}
1
2
3
4
5
public class MallarDuck extends Duck {
public MalllardDuck() {
flyb = new HighFlyBehavior();
}
}
1
2
3
4
5
public class NanoDuck extends Duck {
public MalllardDuck() {
flyb = new SpaceFlyBehavior();
}
}

另外,在鸭子类中应用behavior类时,需要注意:
针对接口编程,而不是针对具体实现编程。

也就是我们在鸭子类中的依赖应该是抽象behavior类引用,而不是behavior的具体实现类,否则会造成鸭子类behavior限定于某个实现类,不利于后面的改变扩展。

  • 进一步增强,实现动态设定行为。

前面我们通过在鸭子类内部引用behaviour类来完成具体行为,具体是在鸭子类构造函数内完成behaviour的实例化。由于具体行为是由behaviour类的实例完成,这也就是给我们提供了动态改变鸭子实例的行为,比如通过setFlyBehaviour(FlyBehavior fb)方法设定新的行为实现类,我们便可以在运行时改变鸭子的行为。

1
2
3
4
5
6
7
8
9
10
11
public class Duck {
FlyBehaviour flyb;

public void performFly() {
flyb.fly();
}

public void setFlyBehaviour(FlyBehavior fb) {
flyb = fb;
}
}

Summary

很多时候”有一个”可能比”是一个”更好,这也是一个重要的设计原则:
多用组合,少用继承。
前面提到的还有:
找出应用中可能需要变化之处,把它们独立出来,不要和哪些不需要变化的代码混在一起。
针对接口编程,而不是针对具体实现编程。

使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以在运行时动态的改变行为,只要组合的行为对象符合正确的接口标准即可。

Strategy Pattern

前面使用的模式就是策略模式。策略模式定义了算法族,并分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的类。